﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;

namespace FileRenamer
{
	public class Commands : List<ICommand>
	{
		[ImportMany]
		IEnumerable<Lazy<ICommand>> newCommands;

		private CompositionContainer container;
		public Commands()
		{
			var catalog = new AggregateCatalog();
			//add built-in commands
			catalog.Catalogs.Add(new AssemblyCatalog(typeof(Commands).Assembly));
			//add any new commands
			if (Globals.Settings != null && Globals.Settings.EnableExtensions)
				catalog.Catalogs.Add(new DirectoryCatalog(Globals.ExtensionFolder));

			container = new CompositionContainer(catalog);
			try
			{
				this.container.ComposeParts(this);
			}
			catch (CompositionException compEx)
			{
				MessageBox.Show("Problem Importing Commands\n\n" + compEx.Message);
			}
			foreach (Lazy<ICommand> i in newCommands)
			{
				this.Add(i.Value);
			}

		}
		public new void Add(ICommand obj)
		{
			if (this.FirstOrDefault(i => i.CommandName == obj.CommandName) == null) base.Add(obj);
			else throw new Exception("Command text must be unique. Conflict wtih: " + obj.CommandName);
		}
		public List<string> CommandNames()
		{
			return this.Select(c => c.CommandName).ToList();
		}
	}

	#region Insert Command
	[Export(typeof(ICommand))]
	public class InsertCommand : ICommand
	{
		public string Name
		{
			get { return "Insert"; }
		}

		public string Description
		{
			get { return "Inserts text at the specified position.\nCommand: ins(index,text)\n\tUse a negative index to count from end of string."; }
		}

		public string CommandName
		{
			get { return "ins"; }
		}

		public string Convert(string input, string[] args)
		{
			int pos;
			char direction;
			if (!parseInt(args[0], out direction, out pos))
				throw new Exception("Could not parse the first arguement of the 'ins' command.", new Exception("The type should be of integer."));

			string insertText = args[1];

			if (direction == '-')
				return input.Insert(input.Length - -pos, insertText);
			
			return input.Insert(pos, insertText);
		}

		private bool parseInt(string text, out char direction, out int value)
		{
			direction = text[0] == '-' ? '-' : '+';
			return int.TryParse(text, out value);
		}

		public string LoadXaml(ref Grid container)
		{
			return "";
		}
	}
	#endregion

	#region Casing Command
	[Export(typeof(ICommand))]
	public class CasingCommand : ICommand
	{
		public string Name
		{
			get { return "Casing"; }
		}

		public string Description
		{
			get
			{
				return "Manipulate the casing of the string.\nCommand: cas(upper|lower,first|all|split,delimeter)\n\t" +
					"first: only change first char.\n\t" +
					"all: change all chars\n\tsplit: change first and all after the specified delimiter.";
			}
		}

		public string CommandName
		{
			get { return "cas"; }
		}

		public string Convert(string input, string[] args)
		{
			char dir = args[0][0];
			char which = args[1][0];
			string splitter = "";
			if (args.Length > 2) splitter = args[2];

			int position = 0;
			switch (which)
			{
				case 'a':		//all
					return dir == 'l' ? input.ToLower() : input.ToUpper();
				case 'f':		//first
					for (int i = 0; i < input.Length; i++)
					{
						if (Char.IsLetter(input[i]))
						{
							position = i;
							break;
						}
					}
					if (dir == 'l')
						return input.Substring(0, position) + input.Substring(position, 1).ToLower() + input.Substring(position + 1);
					else
						return input.Substring(0, position) + input.Substring(position, 1).ToUpper() + input.Substring(position + 1);
				case 's':		//single after delimeter
					if (!String.IsNullOrEmpty(splitter))
					{
						while (position < input.Length)
						{
							position = input.IndexOf(splitter, position + 1);
							if (position == -1) break;
							String first = input.Substring(0, position + 1);
							String target = input[position + splitter.Length].ToString();
							target = dir == 'l' ? target.ToLower() : target.ToUpper();
							String end = input.Substring(position + splitter.Length + 1);
							input = first + target + end;
						}
						if (dir == 'l' && args.Length < 4)
						{
							return input.Substring(0, 1).ToLower() + input.Substring(1);
						}
						else
						{
							return input.Substring(0, 1).ToUpper() + input.Substring(1);
						}
					}
					break;
			}
			return input;
		}

		public string LoadXaml(ref Grid container)
		{
			return "";
		}
	}
	#endregion

	#region Replace Command
	[Export(typeof(ICommand))]
	public class ReplaceCommand : ICommand
	{
		public string Name
		{
			get { return "Replace"; }
		}

		public string Description
		{
			get { return "Replace Text"; }
		}

		public string CommandName
		{
			get { return "rep"; }
		}

		public string Convert(string input, string[] args)
		{
			char mode = args[0][0].ToString().ToLower().Trim()[0];
			string replaceText = args[1];
			string newText = args[2];
			bool matchCase = true;
			if (args.Length > 3) matchCase = args[3].Trim().ToLower().StartsWith("c");

			if (input.IndexOf(replaceText, matchCase ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase) != -1)
			{
				if (mode == 'a')
				{
					return Regex.Replace(input, replaceText, newText, matchCase ? RegexOptions.None : RegexOptions.IgnoreCase);
				}
				if (mode == 'l')
				{
					int oldTextStart = input.LastIndexOf(replaceText, matchCase ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase);
					String beginning = input.Substring(0, oldTextStart);
					String end = input.Substring(oldTextStart + replaceText.Length);
					return beginning + newText + end;
				}
				else //mode = first only
				{
					return input.Substring(0, input.IndexOf(replaceText, matchCase ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase)) + newText +
						input.Substring(input.IndexOf(replaceText, matchCase ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase) + replaceText.Length);
				}
			}
			else
			{
				return input;
			}
		}

		public string LoadXaml(ref Grid container)
		{
			return "";
		}
	}
	#endregion

	#region Remove Command
	[Export(typeof(ICommand))]
	public class RemoveCommand : ICommand
	{
		public string Name
		{
			get { return "Remove"; }
		}

		public string Description
		{
			get { return "Remove text"; }
		}

		public string CommandName
		{
			get { return "rem"; }
		}

		public string Convert(string input, string[] args)
		{
			int startIndex;
			char startDirection;
			if (parseInt(args[0], out startDirection, out startIndex))
			{
				if (args.Length > 1)
				{
					int count;
					if (int.TryParse(args[1], out count))
					{
						if (startDirection == '+')
							return input.Remove(startIndex, count);
						else
							return input.Remove(input.Length + startIndex, count);
					}
					throw new Exception("Could not parse the second arguement of the rem command", new Exception("Looking for int but found something else."));

				}
				else
				{
					if (startDirection == '+')
						return input.Remove(startIndex);
					else
						return input.Remove(input.Length + startIndex);
				}
			}
			throw new Exception("Could not parse the first arguement of the rem command", new Exception("Looking for int but found something else."));
		}

		private bool parseInt(string text, out char direction, out int value)
		{
			if (text[0] == '-') direction = '-';
			else direction = '+';
			return int.TryParse(text, out value);
		}

		public string LoadXaml(ref Grid container)
		{
			return "";
		}
	}
	#endregion

}
